﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;

namespace CreatePerformanceCounters
{
    internal class PerformanceCounterController : IPerformanceCounterController
    {
        private List<PerformanceCounterCategory> DeserializeCounters(string json)
        {
            return JsonConvert.DeserializeObject<List<PerformanceCounterCategory>>(json);
        }

        public List<PerformanceCounterCategory> Validate(string json)
        {
            ValidateNullOrEmptyString(json);

            List<PerformanceCounterCategory> counters = null;

            try
            {
                counters = DeserializeCounters(json);
                Validate(counters);
            }
            catch (Newtonsoft.Json.JsonException ex)
            {
                Trace.Write(ex.ToString());
                throw new ArgumentException();
            }
            catch (Exception ex)
            {
                Trace.Write(ex.ToString());
                throw;
            }

            return counters;
        }

        private void Validate(List<PerformanceCounterCategory> counters)
        {
            StringBuilder sb = new StringBuilder();
            foreach (var item in counters)
            {
                ValidateCounterCategories(item, sb);
            }

            if (sb.Length > 0)
            {
                throw new ArgumentException(sb.ToString());
            }
        }

        private void ValidateCounterCategories(PerformanceCounterCategory item, StringBuilder sb)
        {
            StringBuilder sbCategory = new StringBuilder();
            StringBuilder sbCounters = new StringBuilder();

            bool isValid = ValidateCounterCategoryName(item, sbCategory) & 
                ValidateCounterCategoryType(item, sbCategory) &
                ValidateCounters(item.Counters, sbCounters);

            if (!isValid)
            {
                sb.AppendLine(GetCategoryPrint(item));

                if (sbCategory.Length > 0)
                {
                    sb.AppendLine(sbCategory.ToString());
                }

                if (sbCounters.Length > 0)
                {
                    sb.AppendLine(sbCounters.ToString());
                }
            }
        }

        private string GetCategoryPrint(PerformanceCounterCategory item)
        {
            return string.Format(Messages.CategoryPrint,
                item.Name,
                item.Help,
                item.Type);
        }

        private bool ValidateCounters(List<PerformanceCounter> list, StringBuilder sb)
        {
            bool isValid = true;

            if (list.Count == 0)
            {
                isValid = false;
                sb.Append(Messages.CategoryWithNoCounters);
            }
            else
            {
                foreach (var item in list)
                {
                    StringBuilder sbCounter = new StringBuilder();
                    bool isCounterValid = ValidateCounter(item, sbCounter);
                    isValid &= isCounterValid;

                    if (!isCounterValid)
                    {
                        sb.AppendLine(GetCounterPrint(item));
                        if (sbCounter.Length > 0)
                        {
                            sb.AppendLine(sbCounter.ToString());
                        }
                    }
                }
            }

            return isValid;
        }

        private string GetCounterPrint(PerformanceCounter item)
        {
            return string.Format(Messages.CounterPrint,
                item.Name,
                item.Help,
                item.Type);
        }

        private bool ValidateCounter(PerformanceCounter item, StringBuilder sb)
        {
            return ValidateCounterName(item, sb) &
                ValidateCounterType(item, sb);
        }

        private bool ValidateCounterType(PerformanceCounter item, StringBuilder sb)
        {
            bool isValid = false;

            if (item.Type == null)
            {
                sb.Append(Messages.NullPerformanceCounterType);
            }
            else
            {
                isValid = true;
            }

            return isValid;
        }

        private bool ValidateCounterName(PerformanceCounter item, StringBuilder sb)
        {
            bool isValid = false;

            if (item.Name == null)
            {
                sb.Append(Messages.NullPerformanceCounterName);
            }
            else if (item.Name == string.Empty)
            {
                sb.Append(Messages.EmptyPerformanceCounterName);
            }
            else
            {
                isValid = true;
            }

            return isValid;
        }

        private bool ValidateCounterCategoryType(PerformanceCounterCategory item, StringBuilder sb)
        {
            bool isValid = false;

            if (item.Type == null)
            {
                sb.Append(Messages.NullCategoryType);
            }
            else if (!ValidateCategoryTypeValue(item.Type.Value))
            {
                sb.Append(Messages.WrongCategoryType);
            }
            else
            {
                isValid = true;
            }

            return isValid;
        }

        private bool ValidateCategoryTypeValue(int typeValue)
        {
            var enumValues = Enum.GetValues(typeof(PerformanceCounterCategoryType));

            foreach (int item in enumValues)
            {
                if (item == typeValue)
                {
                    return true;
                }
            }

            return false;
        }

        private bool ValidateCounterCategoryName(PerformanceCounterCategory item, StringBuilder sb)
        {
            bool isValid = false;

            if (item.Name == null)
            {
                sb.Append(Messages.NullCategoryName);
            }
            else if (item.Name == string.Empty)
            {
                sb.Append(Messages.EmptyCategoryName);
            }
            else
            {
                isValid = true;
            }

            return isValid;
        }

        private void ValidateNullOrEmptyString(string json)
        {
            if (json == null)
            {
                throw new ArgumentNullException();
            }

            if (json == string.Empty)
            {
                throw new ArgumentOutOfRangeException();
            }
        }

        public void Create(string json)
        {
            var categories = Validate(json);

            if (categories != null && categories.Count > 0)
            {
                Repository.Create(categories);
            }
        }
        private IPerformanceCounterRepository Repository { get; set; }
        public PerformanceCounterController()
        {
            Repository = new PerformanceCounterRepository();
        }

        public PerformanceCounterController(IPerformanceCounterRepository repository)
        {
            Repository = repository;
        }
    }
}